import {ObjectID} from "mongodb";

import fs = require('fs');
import path = require('path');
import mkdirp = require('mkdirp');
import {Request} from "express";
import { Promise } from "es6-promise";

import * as Utils from './utils';
import {Magics} from "./magics";
import {ErrCode} from "./error.code";

export default class DiskStorage {
    private path: string;
    private basePath: string;

    constructor(path: string){
        this.basePath = Magics.UploadBasePath;
        this.path = this.basePath + path;
    }

    name() { return `DiskStorage`; }

    _getFileName(file: any): string {
        let indx = file && file['originalname'] && file['originalname'].lastIndexOf('.');
        let ext = indx != -1 ? file['originalname'].substr(indx) : '.JPG';
        return Utils.md5(new ObjectID().toString()).substr(7, 16) + ext;
    }

    _getDestination(): string{
        mkdirp.sync(this.path);
        return this.path;
    }

    _handleFile(req: Request, file: any, cb: Function){
        let destination = this._getDestination();
        let filename = this._getFileName(file);
        let finalPath = path.join(destination, filename);
        let outStream = fs.createWriteStream(finalPath);
        let result = {
            path: finalPath,
            filename: filename,
            destination: destination
        };
        file['stream'].pipe(outStream);
        outStream.on('error', cb);
        outStream.on('finish', () => {
            result['size'] = outStream.bytesWritten;
            cb(null, result);
        })
    }

    _removeFile(req: Request, file: any, cb){
        let path = file['path'];
        delete file['destination'];
        delete file['filename'];
        delete file['path'];

        if(path) {
            fs.unlink(path, cb);
        } else {
            cb(null);
        }
    }

    rename(origin: string, dest: string){
        let base = this._getDestination();
        let originPath = path.join(base, origin);
        let destPath = path.join(base, dest);
        return new Promise((resolve, reject) => {
            if(!origin || !dest){
                reject({err_code: ErrCode.ArgsInvalid});
            } else{
                fs.renameSync(originPath, destPath);
                resolve();
            }
        })
    }
}
